package com.iteaj.iot.boot;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ClassUtil;
import com.iteaj.iot.*;
import com.iteaj.iot.boot.core.IotCoreConfiguration;
import com.iteaj.iot.business.ProtocolHandleFactory;
import com.iteaj.iot.client.component.SocketClientComponent;
import com.iteaj.iot.codec.filter.CombinedInterceptor;
import com.iteaj.iot.codec.filter.DecoderInterceptor;
import com.iteaj.iot.event.FrameworkEventListener;
import com.iteaj.iot.server.SocketServerComponent;
import com.iteaj.iot.websocket.WebSocketInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@AutoConfigureAfter(IotCoreConfiguration.class)
public class IotApplication implements ApplicationRunner, DisposableBean {

    private List<LifeCycle> remainLifeCycles;
    private final IotThreadManager threadManager;
    private final IotCoreProperties coreProperties;
    private final ComponentFactory componentFactory;
    private final ApplicationContext applicationContext;
    private final ProtocolTimeoutManager timeoutManager;
    private final DeviceManagerFactory deviceManagerFactory;
    private final ProtocolHandleFactory protocolHandleFactory;

    private static Logger logger = LoggerFactory.getLogger(IotApplication.class);

    public IotApplication(IotThreadManager threadManager, IotCoreProperties coreProperties, ComponentFactory componentFactory
            , ApplicationContext applicationContext, ProtocolHandleFactory protocolHandleFactory
            , ProtocolTimeoutManager timeoutManager, @Autowired(required = false) DeviceManagerFactory deviceManagerFactory) {
        this.threadManager = threadManager;
        this.coreProperties = coreProperties;
        this.timeoutManager = timeoutManager;
        this.componentFactory = componentFactory;
        this.applicationContext = applicationContext;
        this.protocolHandleFactory = protocolHandleFactory;
        this.deviceManagerFactory = deviceManagerFactory;
    }

    @Override
    public void run(ApplicationArguments args) throws Exception {
        remainLifeCycles = applicationContext
                .getBeanProvider(LifeCycle.class)
                .stream().filter(item ->
                        !(item instanceof IotThreadManager)
                                && !(item instanceof ComponentFactory)
                                && !(item instanceof FrameworkComponent)
                                && !(item instanceof ProtocolTimeoutManager))
                .collect(Collectors.toList());

        List<LifeCyclePostProcessor> processors = applicationContext
                .getBeanProvider(LifeCyclePostProcessor.class)
                .stream()
                .collect(Collectors.toList());

        try {
            // 初始化所有组件
            initFramework();

            // 所有组件已经初始化完成
            processors.forEach(item -> item.postProcessBeforeStart());

            // 启动所有生命周期组件
            startLifeCycle(remainLifeCycles);

            // 所有组件已经启动完成
            processors.forEach(item -> item.postProcessAfterStart());

        } catch (Exception e) {
            closeAll();

            throw e;
        }

    }

    private void closeAll() {
        this.threadManager.close();
        this.timeoutManager.close();
        this.componentFactory.close();
        if(CollectionUtil.isNotEmpty(remainLifeCycles)) {
            remainLifeCycles.forEach(item -> {
                try {
                    item.close();
                } catch (Exception ex) {
                    logger.error("调用生命周期失败", ex);
                }
            });
        }
    }

    private void startLifeCycle(List<LifeCycle> lifeCycles) {
        // 启动其它的生命周期组件
        if(CollectionUtil.isNotEmpty(lifeCycles)) {
            lifeCycles.forEach(item -> item.start(null));
        }

        // 启动所有组件
        componentFactory.start((Object) null);

        // 启动协议超时管理器
        timeoutManager.start(null);
    }

    private void initFramework() {
        List<FrameworkEventListener> listeners = applicationContext
                .getBeanProvider(FrameworkEventListener.class)
                .stream().collect(Collectors.toList());

        Map<? extends Class<?>, DecoderInterceptor> filterMap = applicationContext
                .getBeanProvider(DecoderInterceptor.class)
                .stream()
                .filter(item -> !(item instanceof FrameworkComponent))
                .collect(Collectors.toMap(item -> ClassUtil.getTypeArgument(item.getClass()), item -> item));

        // 构建框架各个组件管理器
        FrameworkManager.getInstance()
                .build(listeners, this.threadManager, this.componentFactory
                        , this.protocolHandleFactory, this.timeoutManager, this.deviceManagerFactory);

        // 注册组件
        applicationContext.getBeanProvider(FrameworkComponent.class).forEach(item -> {
            componentFactory.register(item);
            if(item.getInterceptor() == CombinedInterceptor.DEFAULT
                    || item.getInterceptor() == WebSocketInterceptor.DEFAULT
                    || item.getInterceptor() == DecoderInterceptor.DEFAULT) {

                DecoderInterceptor filter = filterMap.get(item.getClass());
                if(filter != null) {
                    if(item instanceof SocketServerComponent) {
                        if(filter instanceof CombinedInterceptor) {
                            ((SocketServerComponent<?, ?>) item).setInterceptor((CombinedInterceptor) filter);
                        } else {
                            throw new FrameworkException("组件["+item.getClass().getSimpleName()+"]只支持[CombinedInterceptor]拦截器");
                        }
                    } else if(item instanceof SocketClientComponent) {
                        ((SocketClientComponent<?, ?>) item).setInterceptor(filter);
                    }
                }
            }
        });

        // 注册协议处理器
        applicationContext.getBeanProvider(ProtocolHandle.class).forEach(item -> {
            protocolHandleFactory.register(item);
        });
    }

    @Bean
    @Order
    public LoggerLifeCyclePostProcessor loggerLifeCyclePostProcessor() {
        return new LoggerLifeCyclePostProcessor();
    }

    @Override
    public void destroy() throws Exception {
//        closeAll();
    }
}
